from time import time, localtime
import os
from Tools.console import print as p
import json


ANSWER_CACHE_PATH = "./public/ANSWER"
ROOT_PATH = os.getcwd()


class ValidFilenameError(Exception):
    pass


class Filename:

    prefix = ""
    suffix = ""

    filename = ""
    filename_list = None

    children = None
    parent = None

    def __init__(self):
        self.filename_list = []
        self.children = []

    def encode(self):
        prefix = None
        suffix = None
        if self.parent != None:
            prefix = self.parent.filename
            suffix = self.find_name_in_from_children()

        else:
            (year, month, day, hour, minute, second, _, _, _) = localtime(time())
            prefix = "-".join(map(str, [year, month,
                              day, hour, minute, second]))

        self.prefix = prefix
        self.suffix = suffix
        self.filename = self.prefix + \
            ('' if self.suffix == None else ('-' + self.suffix))

    def decode(self, s: str):
        tokens = s.split("-")
        if len(tokens) < 6:
            raise ValidFilenameError

        self.prefix = "-".join(tokens[:-1]
                               ) if len(tokens) > 6 else "-".join(tokens)
        self.suffix = "-".join(tokens[-1:]) if len(tokens) > 6 else ""
        self.filename = self.prefix if self.suffix == "" else self.prefix + "-" + self.suffix
        self.filename_list = tokens

    def find_name_in_from_children(self):
        if self.parent == None:
            return None
        children = list(
            filter(lambda el: not self.is_me(el), self.parent.children))
        if len(children) == 0:
            return '1'
        children = sorted(children,
                          key=lambda item: int(item.suffix))

        return str(int(children[-1:][0].suffix) + 1)

    def is_my_child_by_instance(self, instance) -> bool:
        return self.is_my_child_by_name(instance.filename)

    def is_my_child_by_name(self, filename) -> bool:
        if filename.startswith(self.filename) and len(self.filename) < len(filename) and self.filename == "-".join(filename.split("-")[:-1]):
            return True
        return False

    def is_me(self, instance) -> bool:
        return self == instance

    def is_parent(self, instance=None, name: str = None) -> bool:
        if instance != None:
            return instance.filename == "-".join(self.filename_list[:-1])
        return False

    def remove_self(self):
        if self.parent is None:
            return True
        children = self.parent.children
        for index, ele in enumerate(children):
            if (self.is_me(ele)):
                children.pop(index)
                return True
        return False

    def append(self, child):
        if not isinstance(child, Filename):
            return
        child.parent = self
        self.children.append(child)

    def new(s: str):
        f = Filename()

        f.decode(s)
        return f

    def is_valid_filename(filename: str) -> bool:
        tokens = filename.split('-')
        if len(tokens) < 6:
            return False
        return True


class Restore:

    public_path: str = os.path.join(ROOT_PATH, ANSWER_CACHE_PATH)

    store_files = None

    current_filename: Filename = None

    def __init__(self):
        self.store_files = []

    def apply(self):
        if not os.path.isdir(self.public_path):
            os.mkdir(self.public_path)
        self.rebuild_from_files()

    def rebuild_from_files(self):
        files = os.listdir(self.public_path)

        files = list(filter(Filename.is_valid_filename, files))

        flat_map = {}
        flat_set = []
        roots = []

        for filename in files:
            file = Filename()
            file.decode(filename)
            if flat_map.get(file.prefix) is None:
                flat_map[file.prefix] = []

            flat_map[file.prefix].append(file)
            flat_set.append(file)

        for filename in flat_set:
            flat_set_item = flat_map.get(filename.filename)
            if flat_set_item is None:
                continue

            for item in flat_set_item:
                if filename.is_me(item):
                    continue
                filename.append(item)

        self.store_files = list(filter(lambda el: el.parent is None, flat_set))
        flat_set = None
        flat_map = None

    def print(self, data=None, ident=0, prefix=""):
        if data is None:
            return
        if len(data) == 0:
            return

        for index, item in enumerate(data, start=1):
            p("{}: {}".format(prefix + str(index),
              item.filename).rjust(len(item.filename) + ident))
            self.print(item.children, ident + 4)

    def read(self, filename: Filename):
        if filename is None:
            return
        with open(os.path.join(self.public_path, filename.filename), 'r', encoding = 'utf-8') as fp:
            return json.loads(fp.read())

    def write(self, data):
        filename = self.current_filename
        if filename is None:
            filename = Filename()
            filename.encode()
        print(os.path.join(self.public_path, filename.filename))
        with open(os.path.join(self.public_path, filename.filename), 'w', encoding = 'utf-8') as fp:
            fp.write(json.dumps(data, indent=None))

    def find_by_key_list(self, keys):
        result = self.store_files
        while len(keys) > 0:
            if not isinstance(result, list):
                result = result.children
            key = keys.pop(0)
            try:
                result = result[int(key) - 1]
            except:
                return None
        return result


if __name__ == "__main__":

    parent = Filename()

    child1 = Filename()
    child2 = Filename()

    parent.encode()

    parent.append(child1)
    child1.encode()
    parent.append(child2)
    child2.encode()

    child1_child1 = Filename()

    child1.append(child1_child1)
    child1_child1.encode()
    print(parent.filename, child1.filename,
          child2.filename, child1_child1.filename)

    Restore().apply()
